mTLS self-signed pubkey-only certs
2022-04-06 ยท 2 min read
Assuming you already have PKI set up to distribute pubkeys everywhere, this crate allows you to
- easily generate valid self-signed certs from a keypair.
- server and client verifiers that check whether the peer pubkey is as we expect.
Just like our old NoiseIX handshake code (which was simpler IMO : ))
// rccheck/src/ed25519_certgen.rs
fn gen_certificate(
subject_names: impl Into<Vec<String>>,
key_pair: (&[u8], &'static SignatureAlgorithm),
) -> Result<rustls::Certificate, anyhow::Error> {
let kp = KeyPair::from_der_and_sign_algo(key_pair.0, key_pair.1)?;
let mut cert_params = CertificateParams::new(subject_names);
cert_params.key_pair = Some(kp);
cert_params.distinguished_name = rcgen::DistinguishedName::new();
cert_params.alg = key_pair.1;
let cert = rcgen::Certificate::from_params(cert_params).expect(
"unreachable! from_params should only fail if the key is incompatible with params.algo",
);
let cert_bytes = cert.serialize_der()?; // <- also signs
Ok(rustls::Certificate(cert_bytes))
}
simple Rust library to gen x509 certs #
// rcgen/lib.rs
impl CertificateParams {
// ..
fn serialize_der_with_signer<K: PublicKeyData>(&self, pub_key: &K, ca :&Certificate) -> Result<Vec<u8>, RcgenError> {
yasna::try_construct_der(|writer| {
writer.write_sequence(|writer| {
let tbs_cert_list_serialized = yasna::try_construct_der(|writer| {
self.write_cert(writer, pub_key, ca)?;
Ok::<(), RcgenError>(())
})?;
// Write tbsCertList
writer.next().write_der(&tbs_cert_list_serialized);
// Write signatureAlgorithm
ca.params.alg.write_alg_ident(writer.next());
// Write signature
ca.key_pair.sign(&tbs_cert_list_serialized, writer.next())?;
Ok(())
})
})
}
// ..
}